#include "Executor.h"

#include <iostream>

#include <boost/variant/variant.hpp>
#include <boost/variant/get.hpp>

Executor::Executor(const std::shared_ptr<TaskLauncher>& launcher,
                   const std::shared_ptr<Printer>& printer) :

                   launcher_(launcher),
                   printer_(printer) { }

FilePairsType Executor::run(
              std::function<AlgResultType(const FilePairType&)> func, 
              const FilePairsType& input_pairs) {
    
    typedef std::pair<FilePairType, AlgResultType> ResultType;

    FilePairsType pairs;

    std::vector<std::future<ResultType>> results;

    printer_->startSession(input_pairs.size());

    auto end = input_pairs.end();
    for (auto iter = input_pairs.begin(); iter != end; ++iter) {
        results.push_back(
            launcher_->launch([iter, this, func] {
                auto sim = func(*iter);
                this->printer_->printAndSync(*iter, sim);
                return std::make_pair(*iter, sim);
            })
        );
    }

    for (auto iter = results.begin(); iter != results.end(); ++iter) {
        auto res = iter->get();
        if (res.second.which() == 1 &&
            boost::get<OptionalResult>(res.second) == UNKNOWN) {

            pairs.push_back(res.first);
        }
    }

    printer_->endSession();

    return pairs;
}


